package com.xinqi.modules.databank.v2.service.resource.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.xinqi.common.base.response.R;
import com.xinqi.common.core.enums.*;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.common.base.dto.QuestionBaseDTO;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.utils.json.JSON;
import com.xinqi.modules.course.chapter.dto.client.CourseChapterClient;
import com.xinqi.modules.course.clazz.client.ClassStudentClient;
import com.xinqi.modules.course.clazz.dto.rsp.ClassStudentResultDTO;
import com.xinqi.modules.databank.dto.req.*;
import com.xinqi.modules.databank.dto.req.question.CommonDataFileDTO;
import com.xinqi.modules.databank.dto.rsp.ResourceResponseDTO;
import com.xinqi.modules.databank.dto.rsp.ResourceStatisticsDTO;
import com.xinqi.modules.databank.dto.rsp.ResourceStatisticsStatsDTO;
import com.xinqi.modules.databank.v2.convert.CommonFileConvert;
import com.xinqi.modules.databank.v2.convert.CourseResourceConvert;
import com.xinqi.modules.databank.v2.convert.CourseResourcePartConvert;
import com.xinqi.modules.databank.v2.domain.CourseResourceEntity;
import com.xinqi.modules.databank.v2.domain.CourseResourcePartEntity;
import com.xinqi.modules.databank.v2.domain.CourseResourceStudentLogEntity;
import com.xinqi.modules.databank.v2.manager.CourseResourceBaseManager;
import com.xinqi.modules.databank.v2.manager.CourseResourcePartManager;
import com.xinqi.modules.databank.v2.manager.CourseResourceStudentLogManager;
import com.xinqi.modules.databank.v2.service.assistant.AssistantListen;
import com.xinqi.modules.databank.v2.service.common.CourseResourceBaseService;
import com.xinqi.modules.databank.v2.service.part.ResourcePartService;
import com.xinqi.modules.databank.v2.service.resource.CourseResourceDataService;
import com.xinqi.modules.databank.v2.service.student.ResourceStudentLogService;
import com.xinqi.modules.databank.v2.service.sync.CourseResourceSyncService;
import com.xinqi.modules.databank.v2.util.ResourceUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 资料库-资料-方法
 * @author dzy
 */
@Service
@RequiredArgsConstructor
public class CourseResourceDataServiceImpl implements CourseResourceDataService {

    private final CourseResourceConvert courseResourceConvert;

    private final CommonFileConvert commonFileConvert;

    private final IdentifierGenerator identifierGenerator;

    private final CourseResourceBaseManager courseResourceBaseManager;
    @Lazy
    private final CourseResourceBaseService courseResourceBaseService;


    private final CourseResourcePartConvert resourcePartConvert;
    private final CourseResourcePartManager resourcePartManager;
    private final ResourcePartService resourcePartService;

    private final CourseResourceStudentLogManager resourceStudentLogManager;
    @Lazy
    private final ResourceStudentLogService resourceStudentLogService;

    @Lazy
    private final CourseChapterClient courseChapterClient;

    private final CourseResourceSyncService resourceSyncService;

    private final AssistantListen assistantListen;

    @Lazy
    private final ClassStudentClient classStudentClient;

    /**
     * 新增 资料
     * @param dataResource 资料添加对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addResource(CourseResourceDataCreateDTO dataResource) {

        // 校验文件是否上传文件
        ResourceUtil.addCheckFile(dataResource);

        // 转换成资料创建对象
        CourseResourceCreateDTO resource = courseResourceConvert.dataCreate(dataResource);

        // 添加创建用户
        resource.setUserId(LoginHelper.getUserId());

        //权限校验
        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        classStudentClient.checkRole(resource.getClassId(), LoginHelper.getUserId(), classRoles);

        // 转换资料库实体
        CourseResourceEntity entity = courseResourceConvert.create(resource);

        // 文件转换生成试题
        List<CourseResourcePartEntity> questionList =
            fileTrans(dataResource.getFileUrls(), dataResource.getVideoUrls(), dataResource.getImageUrls(), entity);

        // 设置类型
        entity.setContentType(CourseContentTypeEnum.DATA.getCode());

        // 设置发布状态
        ResourceUtil.checkTiming(entity);

        // 校验是否是定时发布
        ResourceUtil.checkTime(entity);

        courseResourceBaseManager.save(entity);

        // 保存答题信息
        this.saveQuestions(questionList, entity.getId());

        // 发布状态 同步信息
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), entity.getStatus())) {
            // 同步更新相关数据
            this.syncResourceInfo(entity);
        }

    }


    /**
     * 修改 资料
     * @param dataResource 资料更新对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateResource(CourseResourceDataUpdateDTO dataResource) {

        // 校验资料是否存在
        CourseResourceEntity old = Optional.ofNullable(courseResourceBaseManager.getById(dataResource.getId()))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));

        // 已发布只可以更新结束时间
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), old.getStatus())) {
            CourseResourceEntity updateEntity = new CourseResourceEntity();
            updateEntity.setId(old.getId());
            updateEntity.setEndTime(dataResource.getEndTime());
            courseResourceBaseManager.updateById(updateEntity);
            return;
        }

        // 校验文件是否上传文件
        ResourceUtil.updateCheckFile(dataResource);

        // 更新创建用户
        dataResource.setUserId(LoginHelper.getUserId());

        // 更新章节信息(未设置更新章节字段为0)
        if (Objects.isNull(dataResource.getChapterId())) {
            dataResource.setChapterId(0L);
        }

        //权限校验
        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        classStudentClient.checkRole(old.getClassId(), LoginHelper.getUserId(), classRoles);

        CourseResourceEntity entity = courseResourceConvert.dataUpdate(dataResource);

        // 文件转换生成试题
        List<CourseResourcePartEntity> questionList =
            fileTrans(dataResource.getFileUrls(), dataResource.getVideoUrls(), dataResource.getImageUrls(), entity);

        // 设置资料库类型 为 资料
        entity.setContentType(CourseContentTypeEnum.DATA.getCode());

        // 校验定时发布
        ResourceUtil.checkTiming(entity);

        // 校验发布时间
        ResourceUtil.checkTime(entity);

        // 更新数据
        courseResourceBaseManager.updateById(entity);

        // 保存答题信息
        this.saveQuestions(questionList, entity.getId());

        // 发布状态 同步信息
        if (Objects.equals(YesNoNumberEnum.YES.getCode(), entity.getStatus())) {
            // 同步更新相关数据
            this.syncResourceInfo(entity);
        }
    }

    /**
     * 一键发布 资料 信息
     * @author dzy
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean releaseResourceData(Long id) {
        // 判断是否数据存在
        CourseResourceEntity entity = Optional.ofNullable(courseResourceBaseManager.getById(id))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));

        //权限校验
        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        classStudentClient.checkRole(entity.getClassId(), LoginHelper.getUserId(), classRoles);

        // 更新数据赋值
        entity.setStatus(YesNoNumberEnum.YES.getCode());
        entity.setNowRelease(1);
        entity.setReleaseTime(LocalDateTime.now());
        boolean flag = courseResourceBaseManager.updateById(entity);

        if (flag) {
            // 同步更新相关数据
            this.syncResourceInfo(entity);
        }
        return flag;
    }

    /**
     * 一键发布 资料 信息 V2版本
     * @param id 资料ID
     * @author dzy
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean releaseResourceDataV2(Long id) {
        // 判断是否数据存在
        CourseResourceEntity entity = Optional.ofNullable(courseResourceBaseManager.getById(id))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        CommonErrors.BAD_REQUEST.check(Objects.equals(YesNoNumberEnum.NO.getCode(), entity.getStatus())
            , MessageUtils.message("course.resource.release.valid"));

        //权限校验
        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        classStudentClient.checkRole(entity.getClassId(), LoginHelper.getUserId(), classRoles);

        // 更新数据赋值
        entity.setStatus(YesNoNumberEnum.YES.getCode());
        entity.setNowRelease(YesNoNumberEnum.YES.getCode());
        entity.setTiming(YesNoNumberEnum.NO.getCode());
        entity.setReleaseTime(LocalDateTime.now());
        boolean flag = courseResourceBaseManager.updateById(entity);

        if (flag) {
            // 同步更新相关数据
            this.syncResourceInfo(entity);
        }
        return flag;
    }

    /**
     * 定时发布 资料 信息
     * @param entity 资料实体
     * @author dzy
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean timingPublish(CourseResourceEntity entity) {
        // 更新发布状态
        entity.setStatus(YesNoNumberEnum.YES.getCode());
        // 更新数据
        boolean flag = courseResourceBaseManager.updatePublishById(entity.getId());
        if (flag) {
            // 同步更新相关数据
            this.syncResourceInfo(entity);
        }
        return flag;
    }

    /**
     * 同步对应的资料数据
     */
    public void syncResourceInfo(CourseResourceEntity entity) {
        // 同步更新主表信息
        resourceSyncService.syncResourceContent(entity);
        // 同步学生访问记录
        resourceStudentLogService.syncStudentLog(entity);
        // 课程助手发布消息
        assistantListen.releaseCourseResource(entity.getId(), AssistantMessageTypeEnum.DATA);

        //同步班级
        List<CourseResourceEntity> list = resourceSyncService.syncClass(entity);
        //同步班级试题
        if (CollectionUtils.isNotEmpty(list)) {
            LambdaQueryWrapper<CourseResourcePartEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(CourseResourcePartEntity::getContentId, entity.getId());
            List<CourseResourcePartEntity> partList = resourcePartManager.list(wrapper);
            List<Long> contentIds = list.stream().map(v -> v.getId()).collect(Collectors.toList());
            this.saveBatchQuestions(partList, contentIds);
        }
    }

    /**
     * 下载资料文件
     * @param downloadDto 下载资料实体
     * @return Boolean
     * @author dzy
     */
    @Override
    public List<String> downResourceData(DownloadDTO downloadDto) {

        // 获取 班级学生主信息
        Long userId = LoginHelper.getUserId();
        ClassStudentResultDTO student = R.as(classStudentClient.findVirtualClassStudentByClassIdAndUserId(downloadDto.getClassId(), userId));

        //更新资料下载次数
        if (Objects.nonNull(downloadDto) && CollectionUtils.isNotEmpty(downloadDto.getIds())
            && downloadDto.getIds().size() > 0) {
            List<Long> ids = downloadDto.getIds();

            for (Long id : ids) {
                LambdaUpdateWrapper<CourseResourceStudentLogEntity> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(CourseResourceStudentLogEntity::getContentId, id);
                updateWrapper.eq(CourseResourceStudentLogEntity::getStudentId, student.getStudentId());
                CourseResourceStudentLogEntity studentLogEntity = resourceStudentLogManager.getOne(updateWrapper);
                if (Objects.nonNull(studentLogEntity)) {
                    CourseResourceStudentLogEntity newLogEntity = new CourseResourceStudentLogEntity();
                    Integer count = studentLogEntity.getDownloadNum() == null ? 0 : studentLogEntity.getDownloadNum();
                    newLogEntity.setDownloadNum(count + 1);
                    resourceStudentLogManager.update(newLogEntity, updateWrapper);
                }
            }
        } else {
            CommonErrors.BAD_REQUEST.check(false, "没有可下载的资料信息");
        }
        List<String> downList = courseResourceBaseService.getDownPaths(downloadDto);
        return downList;
    }

    /**
     * 老师端已发布互动课件列表
     * @param contentId 资料ID
     * @return ResourceResponseDTO 返回详情对象
     * @author dzy
     */
    @Override
    public ResourceResponseDTO getResourceDataInfo(Long contentId) {

        // 判断是否数据存在
        CourseResourceEntity entity = Optional.ofNullable(courseResourceBaseManager.getById(contentId))
            .orElseThrow(() -> CommonErrors.NOT_DATA.asException("course.resource.data.id.not.exit"));

        // 获取访问用户信息
        Long userId = LoginHelper.getUserId();
        ClassStudentResultDTO student = R.as(classStudentClient.findByStudentId(entity.getClassId(), userId));

        // 获取班级主学生信息
        ClassStudentResultDTO mainStudent = R.as(classStudentClient.findVirtualClassStudentByClassIdAndUserId(entity.getClassId(), userId));

        ResourceResponseDTO responseDTO = courseResourceBaseManager.getResourceInfo(contentId);
        // 获取所属章节
        if (Objects.nonNull(responseDTO.getChapterId())) {
            String chapterName = R.as(courseChapterClient.selectName(responseDTO.getChapterId()));
            responseDTO.setChapterName(chapterName);
        }
        if (Objects.equals(ClassRoleEnum.REPRESENTATIVE.getCode(), student.getClassRole())
            || Objects.equals(ClassRoleEnum.STUDENT.getCode(), student.getClassRole())) {
            //更新学习学习记录
            LambdaQueryWrapper<CourseResourceStudentLogEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CourseResourceStudentLogEntity::getContentId, contentId);
            queryWrapper.eq(CourseResourceStudentLogEntity::getStudentId, mainStudent.getStudentId());
            CourseResourceStudentLogEntity studentLogEntity = resourceStudentLogManager.getOne(queryWrapper);

            // 判断是否结束
            if (Objects.isNull(entity.getEndTime()) || entity.getEndTime().isAfter(LocalDateTime.now())) {
                // 未结束 更新 学习记录
                this.refreshStudentLog(mainStudent.getStudentId(), studentLogEntity, entity);
            }

            // 给返回值 付用户状态
            if (Objects.nonNull(studentLogEntity)) {
                responseDTO.setStudyStatus(studentLogEntity.getStudyStatus());
            } else {
                responseDTO.setStudyStatus(YesNoNumberEnum.NO.getCode());
            }

        }

        return responseDTO;
    }

    /**
     * 更新 学习记录
     */
    private void refreshStudentLog(Long studentId, CourseResourceStudentLogEntity studentLogEntity, CourseResourceEntity entity) {
        // 判断有无历史学习记录
        if (Objects.nonNull(studentLogEntity)) {
            // 有记录进行记录更新
            LambdaUpdateWrapper<CourseResourceStudentLogEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(CourseResourceStudentLogEntity::getContentId, entity.getId());
            updateWrapper.eq(CourseResourceStudentLogEntity::getStudentId, studentId);
            studentLogEntity.setStudyStatus(StudyingStatusEnum.STUDIED.getCode());
            Integer readNumCount = studentLogEntity.getReadNum() == null ? 1 : studentLogEntity.getReadNum() + 1;
            studentLogEntity.setIsRead(CourseContentReadEnum.READED.getCode());
            studentLogEntity.setReadNum(readNumCount);
            studentLogEntity.setLastAccessTime(LocalDateTime.now());
            // 已结束不做更新
            if (entity.getEndTime().isAfter(LocalDateTime.now())) {
                resourceStudentLogManager.update(studentLogEntity, updateWrapper);
            }
        } else {
            // 没有记录生成新的学习记录
            studentLogEntity = new CourseResourceStudentLogEntity();
            studentLogEntity.setClassId(entity.getClassId());
            studentLogEntity.setStudentId(studentId);
            studentLogEntity.setContentId(entity.getId());
            studentLogEntity.setContentType(entity.getContentType());
            studentLogEntity.setStudyStatus(CourseResourseStudyStatusEnum.STUDIED.getCode());
            studentLogEntity.setIsRead(CourseContentReadEnum.READED.getCode());
            studentLogEntity.setReadNum(1);
            studentLogEntity.setLastAccessTime(LocalDateTime.now());
            // 已结束不做更新
            if (entity.getEndTime().isAfter(LocalDateTime.now())) {
                resourceStudentLogManager.save(studentLogEntity);
            }
        }
    }

    /**
     * 查询资料统计信息
     * @param resourceQueryDTO 课程ID
     * @return List<ResourceStatisticsDTO> 集合
     * @author dzy
     */
    @Override
    public List<ResourceStatisticsDTO> resourceStatistics(ResourceQueryDTO resourceQueryDTO) {
        List<ResourceStatisticsDTO> infos = courseResourceBaseManager.resourceStatistics(resourceQueryDTO);
        return infos;
    }

    /**
     * 查询资料统计信息-带统计信息
     * @param resourceQueryDTO
     * @return List<ResourceStatisticsDTO> 集合
     * @author dzy
     */
    @Override
    public ResourceStatisticsStatsDTO resourceStatisticsALl(ResourceQueryDTO resourceQueryDTO) {

        ResourceStatisticsStatsDTO result = new ResourceStatisticsStatsDTO();

        // 获取统计信息
        ResourceResponseDTO resource = getResourceDataInfo(resourceQueryDTO.getContentId());
        if (Objects.nonNull(resource)) {
            result.setTotal(resource.getTotal());
            result.setUnstudy(resource.getUnstudy());
            result.setStudying(resource.getStudying());
            result.setFinished(resource.getFinished());
        }

        // 获取学生列表
        List<ResourceStatisticsDTO> infos = courseResourceBaseManager.resourceStatistics(resourceQueryDTO);
        result.setList(infos);

        return result;
    }

    /**
     * 添加资料文件转换
     * @author dzy
     */
    private List<CourseResourcePartEntity> fileTrans(List<CommonDataFileDTO> fileUrls, List<CommonDataFileDTO> videoUrls,
                                                     List<CommonDataFileDTO> imageUrls, CourseResourceEntity entity) {
        // 试题信息集合
        List<CourseResourcePartEntity> list = new ArrayList<>();

        // 文档文件转换
        if(CollectionUtils.isNotEmpty(fileUrls)) {
            fileUrls.forEach(item -> {
                if (Objects.isNull(item.getId()) || Objects.equals(0L, item.getId())) {
                    item.setId(identifierGenerator.nextId(null).longValue());
                }
                if (CollectionUtils.isNotEmpty(item.getQuestions())) {
                    item.getQuestions().forEach(question -> {
                        question.setId(identifierGenerator.nextId(null).longValue());
                    });
                    list.add(fileQuestionTranPart(item.getId(), item.getQuestions()));
                    item.setIsQuestion(YesNoNumberEnum.YES.getCode());
                } else {
                    item.setIsQuestion(YesNoNumberEnum.NO.getCode());
                }
            });
            entity.setFileurls(JSON.stringify(commonFileConvert.convert(fileUrls)));
        } else {
            entity.setFileurls(JSON.stringify(new ArrayList<>()));
        }
        // 视频文件转换
        if(CollectionUtils.isNotEmpty(videoUrls)) {
            videoUrls.forEach(item -> {
                if (Objects.isNull(item.getId()) || Objects.equals(0L, item.getId())) {
                    item.setId(identifierGenerator.nextId(null).longValue());
                }
                if (CollectionUtils.isNotEmpty(item.getQuestions())) {
                    item.getQuestions().forEach(question -> {
                        question.setId(identifierGenerator.nextId(null).longValue());
                    });
                    list.add(fileQuestionTranPart(item.getId(), item.getQuestions()));
                    item.setIsQuestion(YesNoNumberEnum.YES.getCode());
                } else {
                    item.setIsQuestion(YesNoNumberEnum.NO.getCode());
                }
            });
            entity.setVideos(JSON.stringify(commonFileConvert.convert(videoUrls)));
        } else {
            entity.setVideos(JSON.stringify(new ArrayList<>()));
        }
        // 图片文件转换
        if(CollectionUtils.isNotEmpty(imageUrls)) {
            imageUrls.forEach(item -> {
                if (Objects.isNull(item.getId()) || Objects.equals(0L, item.getId())) {
                    item.setId(identifierGenerator.nextId(null).longValue());
                }
                if (CollectionUtils.isNotEmpty(item.getQuestions())) {
                    item.getQuestions().forEach(question -> {
                        question.setId(identifierGenerator.nextId(null).longValue());
                    });
                    list.add(fileQuestionTranPart(item.getId(), item.getQuestions()));
                    item.setIsQuestion(YesNoNumberEnum.YES.getCode());
                } else {
                    item.setIsQuestion(YesNoNumberEnum.NO.getCode());
                }
            });
            entity.setImages(JSON.stringify(commonFileConvert.convert(imageUrls)));
        } else {
            entity.setImages(JSON.stringify(new ArrayList<>()));
        }
        return list;
    }

    /**
     * 文件试题转切片数据
     */
    private CourseResourcePartEntity fileQuestionTranPart(Long fileId, List<QuestionBaseDTO> questions) {
        CourseResourcePartEntity entity = new CourseResourcePartEntity();
        entity.setResourceId(fileId);
        entity.setItemType(CourseContentTypeEnum.DATA.getCode());
        entity.setFileType(ResourcePartFileTypeEnum.DATA.getCode());
        entity.setInteractionType(ResourcePartTypeEnum.QUESTION.getCode());
        entity.setQuestions(questions);
        return entity;
    }

    /**
     * 保存资料文件试题
     * @author dzy
     */
    private void saveQuestions(List<CourseResourcePartEntity> partList, Long contentId) {
        partList.forEach(item -> {
            item.setContentId(contentId);
        });
        resourcePartService.deletePart(contentId);
        if (CollectionUtils.isNotEmpty(partList)) {
            resourcePartService.addBatchPart(partList);
        }
    }

    /**
     * 批量-保存资料文件试题
     * @author dzy
     */
    private void saveBatchQuestions(List<CourseResourcePartEntity> partList, List<Long> contentIds) {
        List<CourseResourcePartEntity> newPartList = new ArrayList<>();
        contentIds.forEach(id -> {
            partList.forEach(item -> {
                CourseResourcePartEntity entity = resourcePartConvert.newEntity(item);
                entity.setId(null);
                entity.setContentId(id);
                newPartList.add(entity);
            });
        });
        resourcePartService.deleteBatchPart(contentIds);
        if (CollectionUtils.isNotEmpty(newPartList)) {
            resourcePartService.addBatchPart(newPartList);
        }
    }

}
